/*  
 *  Copyright 2006 Paul Jack.
 *
 *  This file is part of the Dex compiler suite. 
 *  
 *  Dex is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *  
 *  Dex is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */
package dex.compiler.model.definition;

import java.util.List;

import dex.compiler.model.base.ParseNode;
import dex.compiler.model.statement.Comment;
import dex.compiler.model.statement.StatementWalker;


/**
 * Walks a tree of definition nodes.
 */
public abstract class DefinitionWalker extends StatementWalker implements DefinitionVisitor {


	/**
	 * Constructs a new <code>DefinitionVisitor</code>.
	 */
	public DefinitionWalker() {
	}

	
	/**
	 * Walks the given definition.
	 * 
	 * @param definition  the definition to walk
	 */
	public void walk(Definition definition) {
		if (definition == null) {
			throw new IllegalArgumentException("definition must not be null.");
		}
		if (definition instanceof ClassDef) {
			walkClassDef((ClassDef)definition);
			return;
		}
		if (definition instanceof Constructor) {
			walkConstructor((Constructor)definition);
			return;
		}
		if (definition instanceof Function) {
			walkFunction((Function)definition);
			return;
		}
		if (definition instanceof Record) {
			walkRecord((Record)definition);
			return;
		}
		if (definition instanceof TypedName) {
			walkTypedName((TypedName)definition);
			return;
		}
		if (definition instanceof Unit) {
			walkUnit((Unit)definition);
			return;
		}
		throw new AssertionError(definition.getClass().getName());
	}


	private void walkContents(List<ParseNode> nodes) {
		for (ParseNode node: nodes) {
			if (node instanceof Comment) {
				walk((Comment)node);
			} else {
				walk((Definition)node);
			}			
		}
	}


	/**
	 * Walks the given <code>ClassDef</code>.
	 *
	 * @param definition  the definition to walk
	 */
	protected void walkClassDef(ClassDef definition) {
		this.enterClassDef(definition);
		walkContents(definition.getContents());
		this.exitClassDef(definition);
	}


	/**
	 * Walks the given <code>Constructor</code>.
	 *
	 * @param definition  the definition to walk
	 */
	protected void walkConstructor(Constructor definition) {
		this.enterConstructor(definition);
		for (TypedName tn: definition.getParameters()) {
			walk(tn);
		}
		walk(definition.getBody());
		this.exitConstructor(definition);
	}


	/**
	 * Walks the given <code>Function</code>.
	 *
	 * @param definition  the definition to walk
	 */
	protected void walkFunction(Function definition) {
		this.enterFunction(definition);
		for (TypedName tn: definition.getParameters()) {
			walk(tn);
		}
		walk(definition.getBody());
		this.exitFunction(definition);
	}


	/**
	 * Walks the given <code>Record</code>.
	 *
	 * @param definition  the definition to walk
	 */
	protected void walkRecord(Record definition) {
		this.enterRecord(definition);
		walkContents(definition.getContents());
		this.exitRecord(definition);
	}


	/**
	 * Walks the given <code>TypedName</code>.
	 *
	 * @param definition  the definition to walk
	 */
	protected void walkTypedName(TypedName definition) {
		this.visitTypedName(definition);
	}


	/**
	 * Walks the given <code>Unit</code>.
	 *
	 * @param definition  the definition to walk
	 */
	protected void walkUnit(Unit definition) {
		for (ParseNode node: definition.getContents()) {
			if (node instanceof Import) {
				this.visitImport((Import)node);
			} else if (node instanceof Macro) {
				this.visitMacro((Macro)node);
			} else if (node instanceof Comment) {
				walk((Comment)node);
			} else {
				walk((Definition)node);
			}
		}
		this.visitUnit(definition);
	}


}
